// -*- coding: utf-8 -*-
/*
author: zengbin93
email: zeng_bin8888@163.com
create_dt: 2022/12/16 19:37
describe: 统计分析相关功能
*/

use crate::svc::base::{DataFrame, StyleConfig};
use serde_json::Value;
use std::collections::HashMap;

/// 显示分割日统计
pub fn show_splited_daily(df: &DataFrame, config: Option<&StyleConfig>) -> DataFrame {
    let config = config.unwrap_or(&StyleConfig::default());
    
    let mut result = DataFrame::new();
    result.add_column("分割点", crate::svc::base::DataType::String, false);
    result.add_column("样本数", crate::svc::base::DataType::Number, false);
    result.add_column("平均收益", crate::svc::base::DataType::Number, true);
    result.add_column("标准差", crate::svc::base::DataType::Number, true);
    
    result
}

/// 显示年度统计
pub fn show_yearly_stats(df: &DataFrame, config: Option<&StyleConfig>) -> DataFrame {
    let config = config.unwrap_or(&StyleConfig::default());
    
    let mut result = DataFrame::new();
    result.add_column("年份", crate::svc::base::DataType::String, false);
    result.add_column("年化收益", crate::svc::base::DataType::Number, true);
    result.add_column("年化波动率", crate::svc::base::DataType::Number, true);
    result.add_column("夏普比率", crate::svc::base::DataType::Number, true);
    result.add_column("最大回撤", crate::svc::base::DataType::Number, true);
    
    result
}

/// 显示样本内外比较
pub fn show_out_in_compare(df: &DataFrame, config: Option<&StyleConfig>) -> DataFrame {
    let config = config.unwrap_or(&StyleConfig::default());
    
    let mut result = DataFrame::new();
    result.add_column("指标", crate::svc::base::DataType::String, false);
    result.add_column("样本内", crate::svc::base::DataType::Number, true);
    result.add_column("样本外", crate::svc::base::DataType::Number, true);
    result.add_column("差异", crate::svc::base::DataType::Number, true);
    
    result
}

/// 显示按日样本外分析
pub fn show_outsample_by_dailys(df: &DataFrame, config: Option<&StyleConfig>) -> DataFrame {
    let config = config.unwrap_or(&StyleConfig::default());
    
    let mut result = DataFrame::new();
    result.add_column("日期", crate::svc::base::DataType::String, false);
    result.add_column("样本内收益", crate::svc::base::DataType::Number, true);
    result.add_column("样本外收益", crate::svc::base::DataType::Number, true);
    result.add_column("差异", crate::svc::base::DataType::Number, true);
    
    result
}

/// 显示PSI分析
pub fn show_psi(df: &DataFrame, config: Option<&StyleConfig>) -> DataFrame {
    let config = config.unwrap_or(&StyleConfig::default());
    
    let mut result = DataFrame::new();
    result.add_column("变量", crate::svc::base::DataType::String, false);
    result.add_column("PSI", crate::svc::base::DataType::Number, true);
    result.add_column("状态", crate::svc::base::DataType::String, false);
    
    result
}

/// 显示分类统计
pub fn show_classify(df: &DataFrame, config: Option<&StyleConfig>) -> DataFrame {
    let config = config.unwrap_or(&StyleConfig::default());
    
    let mut result = DataFrame::new();
    result.add_column("分类", crate::svc::base::DataType::String, false);
    result.add_column("样本数", crate::svc::base::DataType::Number, false);
    result.add_column("占比", crate::svc::base::DataType::Number, true);
    result.add_column("平均收益", crate::svc::base::DataType::Number, true);
    
    result
}

/// 显示日期效应
pub fn show_date_effect(df: &DataFrame, config: Option<&StyleConfig>) -> DataFrame {
    let config = config.unwrap_or(&StyleConfig::default());
    
    let mut result = DataFrame::new();
    result.add_column("日期类型", crate::svc::base::DataType::String, false);
    result.add_column("平均收益", crate::svc::base::DataType::Number, true);
    result.add_column("标准差", crate::svc::base::DataType::Number, true);
    result.add_column("样本数", crate::svc::base::DataType::Number, false);
    
    result
}

/// 显示正态性检验
pub fn show_normality_check(df: &DataFrame, config: Option<&StyleConfig>) -> DataFrame {
    let config = config.unwrap_or(&StyleConfig::default());
    
    let mut result = DataFrame::new();
    result.add_column("变量", crate::svc::base::DataType::String, false);
    result.add_column("偏度", crate::svc::base::DataType::Number, true);
    result.add_column("峰度", crate::svc::base::DataType::Number, true);
    result.add_column("JB统计量", crate::svc::base::DataType::Number, true);
    result.add_column("P值", crate::svc::base::DataType::Number, true);
    
    result
}

/// 显示描述性统计
pub fn show_describe(df: &DataFrame, config: Option<&StyleConfig>) -> DataFrame {
    let config = config.unwrap_or(&StyleConfig::default());
    
    let mut result = DataFrame::new();
    result.add_column("变量", crate::svc::base::DataType::String, false);
    result.add_column("计数", crate::svc::base::DataType::Number, false);
    result.add_column("均值", crate::svc::base::DataType::Number, true);
    result.add_column("标准差", crate::svc::base::DataType::Number, true);
    result.add_column("最小值", crate::svc::base::DataType::Number, true);
    result.add_column("25%分位数", crate::svc::base::DataType::Number, true);
    result.add_column("50%分位数", crate::svc::base::DataType::Number, true);
    result.add_column("75%分位数", crate::svc::base::DataType::Number, true);
    result.add_column("最大值", crate::svc::base::DataType::Number, true);
    
    result
}

/// 显示DataFrame描述性统计
pub fn show_df_describe(df: &DataFrame, config: Option<&StyleConfig>) -> DataFrame {
    show_describe(df, config)
}

/// 计算PSI (Population Stability Index)
pub fn calculate_psi(expected: &[f64], actual: &[f64], num_bins: usize) -> f64 {
    if expected.len() != actual.len() || expected.is_empty() {
        return 0.0;
    }
    
    let min_val = expected.iter().chain(actual.iter()).fold(f64::INFINITY, |a, &b| a.min(b));
    let max_val = expected.iter().chain(actual.iter()).fold(f64::NEG_INFINITY, |a, &b| a.max(b));
    
    let bin_size = (max_val - min_val) / num_bins as f64;
    let mut expected_bins = vec![0; num_bins];
    let mut actual_bins = vec![0; num_bins];
    
    // 计算预期分布
    for &value in expected {
        let bin_index = ((value - min_val) / bin_size).floor() as usize;
        let bin_index = bin_index.min(num_bins - 1);
        expected_bins[bin_index] += 1;
    }
    
    // 计算实际分布
    for &value in actual {
        let bin_index = ((value - min_val) / bin_size).floor() as usize;
        let bin_index = bin_index.min(num_bins - 1);
        actual_bins[bin_index] += 1;
    }
    
    // 计算PSI
    let total_expected = expected.len() as f64;
    let total_actual = actual.len() as f64;
    let mut psi = 0.0;
    
    for i in 0..num_bins {
        let expected_pct = expected_bins[i] as f64 / total_expected;
        let actual_pct = actual_bins[i] as f64 / total_actual;
        
        if expected_pct > 0.0 && actual_pct > 0.0 {
            psi += (actual_pct - expected_pct) * (actual_pct / expected_pct).ln();
        }
    }
    
    psi
}

/// 计算描述性统计
pub fn calculate_descriptive_stats(data: &[f64]) -> HashMap<String, f64> {
    let mut stats = HashMap::new();
    
    if data.is_empty() {
        return stats;
    }
    
    let n = data.len() as f64;
    let sum: f64 = data.iter().sum();
    let mean = sum / n;
    
    let variance = data.iter()
        .map(|x| (x - mean).powi(2))
        .sum::<f64>() / n;
    let std_dev = variance.sqrt();
    
    let mut sorted_data = data.to_vec();
    sorted_data.sort_by(|a, b| a.partial_cmp(b).unwrap());
    
    let min = sorted_data[0];
    let max = sorted_data[sorted_data.len() - 1];
    let median = if n as usize % 2 == 0 {
        (sorted_data[n as usize / 2 - 1] + sorted_data[n as usize / 2]) / 2.0
    } else {
        sorted_data[n as usize / 2]
    };
    
    let q1_index = (n * 0.25) as usize;
    let q3_index = (n * 0.75) as usize;
    let q1 = sorted_data[q1_index];
    let q3 = sorted_data[q3_index];
    
    // 计算偏度
    let skewness = data.iter()
        .map(|x| ((x - mean) / std_dev).powi(3))
        .sum::<f64>() / n;
    
    // 计算峰度
    let kurtosis = data.iter()
        .map(|x| ((x - mean) / std_dev).powi(4))
        .sum::<f64>() / n - 3.0;
    
    stats.insert("计数".to_string(), n);
    stats.insert("均值".to_string(), mean);
    stats.insert("标准差".to_string(), std_dev);
    stats.insert("最小值".to_string(), min);
    stats.insert("25%分位数".to_string(), q1);
    stats.insert("中位数".to_string(), median);
    stats.insert("75%分位数".to_string(), q3);
    stats.insert("最大值".to_string(), max);
    stats.insert("偏度".to_string(), skewness);
    stats.insert("峰度".to_string(), kurtosis);
    
    stats
}

/// 计算Jarque-Bera统计量
pub fn calculate_jarque_bera_statistic(data: &[f64]) -> (f64, f64) {
    if data.len() < 4 {
        return (0.0, 1.0);
    }
    
    let stats = calculate_descriptive_stats(data);
    let n = data.len() as f64;
    let skewness = stats["偏度"];
    let kurtosis = stats["峰度"];
    
    let jb_statistic = n * (skewness.powi(2) / 6.0 + kurtosis.powi(2) / 24.0);
    
    // 自由度为2的卡方分布
    // 这里使用简化的P值计算，实际应用中可能需要更精确的分布函数
    let p_value = (-jb_statistic / 2.0).exp();
    
    (jb_statistic, p_value)
}

/// 计算日期效应
pub fn calculate_date_effects(returns: &[f64], dates: &[String]) -> HashMap<String, f64> {
    let mut effects = HashMap::new();
    
    if returns.len() != dates.len() || returns.is_empty() {
        return effects;
    }
    
    // 按星期几分组
    let mut weekday_returns: HashMap<String, Vec<f64>> = HashMap::new();
    
    for (i, date_str) in dates.iter().enumerate() {
        // 简化的日期解析，实际应用中需要更robust的日期处理
        if let Some(weekday) = extract_weekday(date_str) {
            weekday_returns.entry(weekday).or_insert_with(Vec::new).push(returns[i]);
        }
    }
    
    // 计算每个星期的平均收益
    for (weekday, returns_list) in weekday_returns {
        let avg_return = returns_list.iter().sum::<f64>() / returns_list.len() as f64;
        effects.insert(weekday, avg_return);
    }
    
    effects
}

/// 提取星期几（简化实现）
fn extract_weekday(date_str: &str) -> Option<String> {
    // 这里是一个简化的实现，实际应用中需要更robust的日期解析
    if date_str.contains("Mon") || date_str.contains("周一") {
        Some("Monday".to_string())
    } else if date_str.contains("Tue") || date_str.contains("周二") {
        Some("Tuesday".to_string())
    } else if date_str.contains("Wed") || date_str.contains("周三") {
        Some("Wednesday".to_string())
    } else if date_str.contains("Thu") || date_str.contains("周四") {
        Some("Thursday".to_string())
    } else if date_str.contains("Fri") || date_str.contains("周五") {
        Some("Friday".to_string())
    } else if date_str.contains("Sat") || date_str.contains("周六") {
        Some("Saturday".to_string())
    } else if date_str.contains("Sun") || date_str.contains("周日") {
        Some("Sunday".to_string())
    } else {
        None
    }
} 